<?php

namespace liketp;

class Response
{
    protected $_varCallFn = '_call';
    protected $defaultCallFn = 'jsonpCall';
    protected $charset = 'utf-8';
    protected $defaultCorsAllowMethods = 'GET,POST,PATCH,PUT,DELETE,OPTIONS';
    protected $defaultCorsAllowHeaders = 'X-Token, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With,Form-type,Referer,Connection,Content-Length,Host,Origin,Authorization,Authori-zation,Accept,Accept-Encoding';

    protected $data;
    protected $content;
    protected $contentType = 'text/html';
    protected $code = 200;
    protected $header = [];
    protected $cookie = [];
    protected $options = [];


    public function __construct($data, int $code = 200)
    {
        $this->init($data, $code);
    }

    public static function create($data = null, string $type = 'html', int $code = 200)
    {
        if (strpos($type, '\\') !== false) {
            $class = $type;
        } else {
            $class = '\\liketp\\response\\' . ucfirst(strtolower($type));
        }
        return App::instance()->make($class, [$data, $code]);
    }

    public function init($data, int $code)
    {
        $this->data($data);
        $this->code($code);
        return $this;
    }

    public function data($data)
    {
        $this->data = $data;
        return $this;
    }

    public function contentType(string $type, string $charset = '')
    {
        $charset = $charset ?: $this->charset;
        $this->header['Content-Type'] = $type . '; charset=' . $charset;
        return $this;
    }

    public function code(int $code)
    {
        $this->code = $code;
        return $this;
    }

    public function header($key, $val = null)
    {
        if (is_array($key)) {
            $this->header = array_merge($this->header, $key);
        } else if (is_string($key)) {
            if (is_null($val)) {
                unset($this->header[$key]);
            } else {
                $this->header[$key] = $val;
            }
        } else {
            throw new \Exception('the type of variable [$key] is not valide');
        }
        return $this;
    }

    public function cookie($key, $val = null, $option = null)
    {
        if (is_array($key)) {
            $this->cookie = array_merge($this->cookie, $key);
        } else if (is_string($key)) {
            if (is_null($val)) {
                unset($this->cookie[$key]);
            } else {
                $this->cookie[$key] = $val;
            }
        } else {
            throw new \Exception('the type of variable [$key] is not valide');
        }
        return $this;
    }

    public function options($origin = null, $methods = null, $headers = null)
    {
        $this->header('Access-Control-Allow-Origin', $origin ?? '*');
        $this->header('Access-Control-Allow-Methods', $methods ?? $this->defaultCorsAllowMethods);
        $this->header('Access-Control-Allow-Headers', $headers ?? $this->defaultCorsAllowHeaders);
        return $this;
    }

    public function content($content)
    {
        if (
            null !== $content &&
            !is_string($content) &&
            !is_numeric($content) &&
            !is_callable([$content, '__toString'])
        ) {
            $msg = sprintf('variable type error: %s', gettype($content));
            throw new \InvalidArgumentException($msg);
        }

        $this->content = (string) $content;
        return $this;
    }

    public function output($data)
    {
        return $data;
    }

    public function getHeader()
    {
        return $this->header;
    }

    public function getContent()
    {
        if (is_null($this->content)) {
            $this->content($this->output($this->data));
        }
        return $this->content;
    }

    public function send()
    {
        $this->contentType($this->contentType);
        $content = $this->getContent();

        if (!headers_sent() && $this->header) {
            $this->outputHeader();
        }

        echo $content;
    }

    //------------------------------------------------ protected
    public function outputHeader()
    {
        http_response_code($this->code);

        foreach ($this->header as $k => $v) {
            header($k . ':' . $v);
        }
    }
}
